using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Tetris
{
    public partial class MainForm : Form
    {
        PathForm pathForm;
        int linesDisintegrated = 0;

        public MainForm()
        {
            InitializeComponent();


            Engine_Init();

            Engine.NewNextBlock += new EventHandler(Engine_NewFutureBlock);
            Engine.AdvancedCalculationsChanged += new EventHandler(Engine_AdvancedCalculationsChanged);

            pathForm = new PathForm();
        }

        void Engine_AdvancedCalculationsChanged(object sender, EventArgs e)
        {
            cbAdvCalc.Checked = Engine.AdvancedCalculations;
        }

        void Engine_Init()
        {
            Engine.Init(
                new Size((int)numWidth.Value, (int)numHeight.Value),
                (int)numRange.Value,
                double.Parse(txtA.Text),
                double.Parse(txtX.Text),
                double.Parse(txtZ.Text),
                cbAdvCalc.Checked,
                cbAdvOpt.Checked,
                (int)numOptLower.Value,
                (int)numOptUpper.Value);
        }

        void Engine_NewFutureBlock(object sender, EventArgs e)
        {
            pnlNextBlock.Invalidate();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            pathForm.StartPosition = FormStartPosition.Manual;
            pathForm.Location = new Point(this.Right, this.Top);
            pathForm.Height = this.Height;
            pathForm.Show();
        }

        private void DoStep()
        {
            int i = Engine.Step();

            Invalidate();

            if (i < 0)
            {
                timer.Stop();
                btnStart.Enabled = false;
                btnStep.Enabled = false;
                btnStop.Enabled = false;
                MessageBox.Show(Properties.Resources.EndOfSimulation);
            }
            else
            {
                linesDisintegrated += i;
                tbLinesRemoved.Text = linesDisintegrated.ToString();
            }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            DoStep();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            btnStop.Enabled = true;
            timer.Start();
        }

        private void btnStep_Click(object sender, EventArgs e)
        {
            DoStep();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            timer.Stop();
        }

        private void btnReset_Click(object sender, EventArgs e)
        {
            Engine_Init();

            Engine.AdvancedCalculations = cbAdvCalc.Checked;
            btnStep.Enabled = true;
            btnStart.Enabled = true;
            linesDisintegrated = 0;
            Invalidate();
        }

        private void speedBar_Scroll(object sender, EventArgs e)
        {
            timer.Interval = Math.Abs(speedBar.Value);
        }

        private bool ParseTextBox(TextBox tb, out double res)
        {
            bool b;
            if ((b = double.TryParse(tb.Text, out res)) == false)
                tb.BackColor = Color.Red;
            else
                tb.BackColor = Color.White;
            return b;
        }

        private void MultiplierTextChanged(object sender, EventArgs e)
        {
            TextBox tb;
            double res;

            switch (((TextBox)sender).Tag.ToString())
            {
                case "A":
                    tb = txtA;
                    if (ParseTextBox(tb, out res)) Engine.HeuristicA = res;
                    break;
                case "X":
                    tb = txtX;
                    if (ParseTextBox(tb, out res)) Engine.HeuristicX = res;
                    break;
                case "Z":
                    tb = txtZ;
                    if (ParseTextBox(tb, out res)) Engine.HeuristicZ = res;
                    break;
            }
        }

        private void miAbout_Click(object sender, EventArgs e)
        {
            new AboutBox().ShowDialog();
        }

        private void MainForm_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
            Engine.PaintBoard(e.Graphics, panel.Location.X, this.Height);
        }

        private void MainForm_Resize(object sender, EventArgs e)
        {
            Invalidate();
        }

        private void miPathForm_Click(object sender, EventArgs e)
        {
            pathForm.Visible = !pathForm.Visible;
        }

        private void miExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void cbUseAdvCalc_CheckedChanged(object sender, EventArgs e)
        {
            Engine.AdvancedCalculations = cbAdvCalc.Checked;
        }

        private void pnlNextBlock_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
            Engine.PaintNextBlock(e.Graphics, pnlNextBlock.Width, pnlNextBlock.Height);
        }

        private void numRange_ValueChanged(object sender, EventArgs e)
        {
            Engine.Range = (int)numRange.Value;
        }

        private void cbShowPath_CheckedChanged(object sender, EventArgs e)
        {
            Engine.ShowPath = cbShowPath.Checked;
        }

        private void numBoundary_ValueChanged(object sender, EventArgs e)
        {
            NumericUpDown n = (NumericUpDown)sender;
            if (n.Tag.ToString() == "U")
            {
                Engine.OptimisationUpperBoundary = (int)n.Value;
            }
            else
                Engine.OptimisationLowerBoundary = (int)n.Value;
                    
        }

        private void cbAdvOpt_CheckedChanged(object sender, EventArgs e)
        {
            Engine.AdvancedOptimisation = cbAdvOpt.Checked;
        }
    }
}